using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UniRx;
using UnityEngine;

namespace EasyLocalization
{
    public abstract class LocalizationDictionary : ScriptableObject
    {
        [SerializeField] Language[] _languages;
        [SerializeField] StringReactiveProperty _currentLanguage;
        
        Dictionary<string, string> _dictionary;
        public IReadOnlyList<Language> languages => _languages;
        public bool isReady => _dictionary != null;
        
        public async UniTask LoadAsync(string language = "",
            IProgress<float> progress = null,
            CancellationToken cancellationToken = default)
        {
            if (string.IsNullOrEmpty(language))
            {
                language = _currentLanguage.Value;
            }
            
            string content = await LoadLanguageAsync(language, progress, cancellationToken);
            _dictionary = Deserialize(content);
            _currentLanguage.Value = language;
        }

        public UniTask ReloadAsync(IProgress<float> progress = null,
            CancellationToken cancellationToken = default)
        {
            UnloadLanguage(_currentLanguage.Value);
            return LoadAsync(_currentLanguage.Value, progress, cancellationToken);
        }

        public IObservable<string> GetValueObservable(string key)
        {
            return _currentLanguage.Select(_ => this[key]);
        }

        public string this[string key]
        {
            get
            {
                if (_dictionary.TryGetValue(key, out string value))
                {
                    return value;
                }

                return key;
            }
            set => _dictionary[key] = value;
        }

        public IEnumerable<string> keys => _dictionary.Keys;

        protected abstract UniTask<string> LoadLanguageAsync(string language,
            IProgress<float> progress = null,
            CancellationToken cancellationToken = default);
        protected abstract void UnloadLanguage(string language);
        protected abstract Dictionary<string, string> Deserialize(string content);
        
        public void Save()
        {
            Save(Serialize(_dictionary));    
        }
        
        protected abstract string Serialize(Dictionary<string, string> dictionary);
        protected abstract void Save(string content);
        
#if UNITY_EDITOR
        public static string currentLanguageFieldName => nameof(_currentLanguage);
#endif
    }
}